package cn.dinxian.activiti.demo2.controller;

import cn.dinxian.activiti.demo2.constent.NumberConstants;
import cn.dinxian.activiti.demo2.service.MyTaskUtil;
import cn.dinxian.activiti.demo2.tool.PageUtils;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import cn.dinxian.entity.ActTaskDTO;
import cn.dinxian.entity.ActWorkflowFormData;
import cn.dinxian.entity.ActWorkflowFormDataDTO;
import cn.dinxian.entity.Base2DTO;
import cn.dinxian.entity.BaseDTO;
import cn.dinxian.entity.CommonResult;
import cn.dinxian.entity.MyProcessDefinition;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author dingxian
 * @Title:
 * @param:
 * @return:
 * @Date 2023/2/28 19:17
 * @Description:
 */
@RestController
@RequestMapping("Repository-provider")
@Slf4j
public class MyRepositoryController {

  @Value("${server.port}")
  private String port;
  @Autowired
  RepositoryService repositoryService;

  @Autowired
  RuntimeService runtimeService;


  @Autowired
  TaskService taskService;
  
  
  @Autowired
  MyTaskUtil myTaskUtil;



  @PostMapping("/ProcessDefinition")
  public CommonResult<MyProcessDefinition> ProcessDefinition(
      MyProcessDefinition param) {
    ProcessDefinitionQuery processInstanceQuery = this.buildProcessInstanceQuery(param);

    param.setCurrent(NumberConstants.Num.ONE);
    param.setPageSize(NumberConstants.Num.EIGHT);

    IPage page = PageUtils.getPage(processInstanceQuery, param);
    page.setRecords(this.assembleProcessDefinition(page.getRecords()));
    MyProcessDefinition result = (MyProcessDefinition) page.getRecords().get(0);
    return new CommonResult<MyProcessDefinition>(200, "完成", result);
  }

  @PostMapping("/getResourceAsStream")
  public void getResourceAsStream(HttpServletResponse response, @RequestBody BaseDTO dto)
      throws IOException {
    String resourceName = dto.getS1();
    String deploymentId = dto.getS2();

    try {
      InputStream resourceAsStream = repositoryService.getResourceAsStream(resourceName,
          deploymentId);

      if (resourceAsStream == null) {
        return;
      }

      response.setCharacterEncoding("utf-8");
      response.setContentType("application/octet-stream");

      response.setHeader("Access-Control-Expose-Headers", "*");
      IOUtils.copy(resourceAsStream, response.getOutputStream());
    } catch (IOException e) {
      e.printStackTrace();

    }
  }

  /**
   * 查询流程数据
   * @param dto
   * @return
   */

  @PostMapping("/selectProcessDefinitionList")
  public List<MyProcessDefinition> selectProcessDefinitionList(
      @RequestBody MyProcessDefinition dto) {

    ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
        .orderByProcessDefinitionId().orderByProcessDefinitionVersion().desc();
    if (StringUtils.isNotBlank(dto.getName())) {
      processDefinitionQuery.processDefinitionNameLike("%" + dto.getName() + "%");
    }
    if (StringUtils.isNotBlank(dto.getKey())) {
      processDefinitionQuery.processDefinitionKeyLike("%" + dto.getKey() + "%");
    }
    List<ProcessDefinition> processDefinitions = processDefinitionQuery.listPage(
        (dto.getCurrent() - 1) * dto.getPageSize(), dto.getPageSize());
    final List<MyProcessDefinition> myProcessDefinitions = this.assembleProcessDefinition(
        processDefinitions);
    return myProcessDefinitions;
  }


  @PostMapping("/deleteProcessDefinition")
  public CommonResult<MyProcessDefinition> deleteProcessDefinition(
      @RequestBody MyProcessDefinition dto) {
    repositoryService.deleteDeployment(dto.getId(), false);
    return new CommonResult<MyProcessDefinition>(200, null);
  }

  @RequestMapping(value = "/uploadStreamAndDeployment", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
  public CommonResult<MyProcessDefinition> uploadStreamAndDeployment(
      @RequestPart("file") MultipartFile file)
      throws IOException {
    // 获取上传的文件名
    String fileName = file.getOriginalFilename();
    // 得到输入流（字节流）对象
    InputStream fileInputStream = file.getInputStream();
    // 文件的扩展名
    String extension = FilenameUtils.getExtension(fileName);
    //zip部署
    if (extension.equals("zip")) {
      ZipInputStream zip = new ZipInputStream(fileInputStream);
      repositoryService.createDeployment()//初始化流程
          .addZipInputStream(zip)
          .deploy();
    } else {
      repositoryService.createDeployment()//初始化流程
          .addInputStream(fileName, fileInputStream)
          .deploy();
    }
    log.info(
        "[MYLOG]:-----MyRepository/uploadStreamAndDeployment==>uploadStreamAndDeployment:[ 部署成功]");
    return new CommonResult<MyProcessDefinition>(200, null);
  }

  @PostMapping("/suspendOrActiveApply")
  public CommonResult<MyProcessDefinition> suspendOrActiveApply(
      @RequestBody MyProcessDefinition dto) {
    final String suspendState = dto.getSuspendState();
    if (("1").equals(suspendState)) {
      repositoryService.suspendProcessDefinitionById(dto.getId());
    } else if (("0").equals(suspendState)) {
      repositoryService.activateProcessDefinitionById(dto.getId());
    }
    return new CommonResult<MyProcessDefinition>(200, null);
  }


  @PostMapping("/addDeploymentByString")
  public CommonResult<MyProcessDefinition> addDeploymentByString(MyProcessDefinition file) {

    repositoryService.createDeployment()
        .addString("CreateWithBPMNJS.bpmn", file.getDescription())
        .deploy();
    return new CommonResult<MyProcessDefinition>(200, null);
  }

  //@PostMapping("/addDeploymentByString")
  //public CommonResult<MyProcessDefinition> addDeploymentByString2(MyProcessDefinition file) {
  //  repositoryService.getBpmnModel(file.getId())
  //      .getFlowElement(file.getId());
  //  repositoryService.createDeployment()
  //      .addString("CreateWithBPMNJS.bpmn", file.getDescription())
  //      .deploy();
  //  return new CommonResult<MyProcessDefinition>(200, null);
  //}

  @PostMapping (value = "/formDataSave")
  public List<ActWorkflowFormData> formDataSave(
      @RequestBody Base2DTO dto) {
     String taskID = dto.getTaskID();
     List<ActWorkflowFormDataDTO> awfs = dto.getActWorkflowFormData();
    final Task task = taskService.createTaskQuery().taskId(taskID).singleResult();

    final ActTaskDTO actTaskDTO = myTaskUtil.assembleTask(task);
    ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
        .processInstanceId(task.getProcessInstanceId()).singleResult();

    Boolean hasVariables = false;//没有任何参数
    HashMap<String, Object> variables = new HashMap<String, Object>();
    //前端传来的字符串，拆分成每个控件
    List<ActWorkflowFormData> acwfds = new ArrayList<>();
    for (ActWorkflowFormDataDTO awf : awfs) {
      ActWorkflowFormData actWorkflowFormData = new ActWorkflowFormData(
          processInstance.getBusinessKey(), awf, actTaskDTO);
      acwfds.add(actWorkflowFormData);
      //构建参数集合
      if (!"f".equals(awf.getControlIsParam())) {
        variables.put(awf.getControlId(), awf.getControlValue());
        hasVariables = true;
      }
    }//for结束
    if (task.getAssignee() == null) {
      taskService.claim(taskID, null);

    }
    if (hasVariables) {
      //带参数完成任务
      taskService.complete(taskID, variables);
    } else {
      taskService.complete(taskID);
    }
    //创建异常
    return acwfds;

  }


  private ProcessDefinitionQuery buildProcessInstanceQuery(MyProcessDefinition request) {
    final ProcessDefinitionQuery processDefinitionQuery = this.repositoryService.createProcessDefinitionQuery();

    if (ObjectUtils.isNotEmpty(request.getDeploymentId())) {
      processDefinitionQuery.deploymentId(request.getDeploymentId());
    }

    return processDefinitionQuery;
  }

  private List<MyProcessDefinition> assembleProcessDefinition(
      List<ProcessDefinition> ProcessDefinition) {
    if (ObjectUtils.isEmpty(ProcessDefinition)) {
      return Lists.emptyList();
    }
    return ProcessDefinition.stream().map(this::assembleProcessDefinition)
        .collect(Collectors.toList());
  }

  private MyProcessDefinition assembleProcessDefinition(ProcessDefinition processDefinition) {

    return MyProcessDefinition.builder()

        .deploymentId(processDefinition.getDeploymentId())
        .resourceName(processDefinition.getResourceName())
        .appVersion(String.valueOf(processDefinition.getAppVersion()))
        .engineVersion(processDefinition.getEngineVersion())
        .tenantId(processDefinition.getTenantId())
        .diagramResourceName(processDefinition.getDiagramResourceName())
        .version(String.valueOf(processDefinition.getVersion()))
        .description(processDefinition.getDescription())
        .key(processDefinition.getKey())
        .name(processDefinition.getName())
        .category(processDefinition.getCategory())
        .id(processDefinition.getId())
        .suspendState(processDefinition.isSuspended() ? "0" : "1")
        .build();

  }

}
